package tiltmaze;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.UIManager;
import tiltmaze.generator.MazeGenerator;
import tiltmaze.loader.MazeLoader;
import tiltmaze.solver.MazeSolver;
import tiltmaze.solver.MazeStateGraph;
import tiltmaze.solver.MazeStatesAnalyzer;
import tiltmaze.view.GeneratorFrame;

/**
 * Main class of the project.
 * @author Juraj Nižnan
 */
public class Main {

    public static void main(String[] args) {
        if (args.length == 0) {
            displayGUI();
        } else {
            if (args[0].equals("-h") & args.length == 1) {
                displayHelp();
                return;
            } else if (args[0].equals("-s")) {
                //SOLVE
                if (args.length == 2) {
                    Maze maze = MazeLoader.importMaze(args[1]);
                    MazeSolver solver = new MazeSolver(maze);
                    solver.solve();
                    System.out.println(solver.getPaths());
                } else if (args.length == 4 && args[2].equals("-gml")) {
                    //with GML generation:
                    Maze maze = MazeLoader.importMaze(args[1]);
                    MazeStateGraph graph = new MazeStateGraph(maze);
                    try {
                        graph.writeGML(args[3]);
                    } catch (IOException ex) {
                        System.err.println("Error writing a graph to " + args[3]);
                    }
                    System.out.println(graph.getSolverPaths());
                } else {
                    displayWrongArgumentsWarning();
                    return;
                }
            } else if (args[0].equals("-g")) {
                //GENERATE
                int r = 2;
                int c = 2;
                int ch = 1;
                int t = 0;
                int fit = 0;
                String o = null;
                String in = null;
                //parse arguments:
                try {
                    r = Integer.parseInt(args[1]);
                    c = r;
                    for (int i = 0; i < args.length / 2 - 1; i++) {
                        String param = args[(i + 1) * 2];
                        if (param.equals("-col")) {
                            c = Integer.parseInt(args[(i + 1) * 2 + 1]);
                        }
                        if (param.equals("-ch")) {
                            ch = Integer.parseInt(args[(i + 1) * 2 + 1]);
                        }
                        if (param.equals("-o")) {
                            o = args[(i + 1) * 2 + 1];
                        }
                        if (param.equals("-in")) {
                            in = args[(i + 1) * 2 + 1];
                        }
                        if (param.equals("-t")) {
                            t = Integer.parseInt(args[(i + 1) * 2 + 1]);
                            t = (t < 0) ? 0 : t;
                        }
                        if (param.equals("-fit")) {
                            fit = Integer.parseInt(args[(i + 1) * 2 + 1]);
                        }
                    }
                } catch (NumberFormatException e) {
                    displayWrongArgumentsWarning();
                    return;
                }
                //generate maze:
                MazeGenerator mg;
                if (in == null) {
                    mg = new MazeGenerator(r, c, ch);
                } else {
                    Maze inMaze = MazeLoader.importMaze(in);
                    if (inMaze == null) {
                        System.err.println("Problems with in file");
                        return;
                    } else {
                        mg = new MazeGenerator(inMaze);
                    }
                }
                mg.setTimeBound(t);
                mg.setFit(fit);
                Maze maze = mg.localSearch();
                MazeSolver solver = new MazeSolver(maze);
                solver.solve();
                if (!solver.getPaths().equals("")) {
                    if (o == null) {
                        System.out.println(maze);
                    } else {
                        try {
                            BufferedWriter out = new BufferedWriter(new FileWriter(o));
                            out.write(maze.toString());
                            out.close();
                        } catch (IOException ex) {
                            System.out.println("Failed to write into " + o);
                            System.out.println(maze);
                        }
                    }
                } else {
                    System.out.println("Maze wasn't created successfully.");
                }
            } else if (args[0].equals("-a")) {
                //ANALYZE
                Maze maze = MazeLoader.importMaze(args[1]);
                MazeStatesAnalyzer msa = new MazeStatesAnalyzer(maze);
                msa.analyze();
                System.out.println(maze.getNumOfRows() + ";"
                        + maze.getNumOfCheckpoints() + ";"
                        + msa.getShortestSolutionLength() + ";"
                        + msa.getNodeCounter() + ";"
                        + msa.getEdgeCounter() + ";"
                        + msa.getNodeDeadlockCounter() + ";"
                        + msa.getEdgeDeadlockCounter() + ";"
                        + msa.getEdgeDeadlocks() + ";"
                        + msa.getSimplifiedGraphEdgeCount() + ";"
                        + msa.getSimplifiedGraphEdgeDeadlocksCount() + ";"
                        + msa.getSimplifiedGraphEdgeDeadlocks());
            } else {
                displayWrongArgumentsWarning();
                return;
            }
        }
    }

    private static void displayHelp() {
        System.out.println("Usage: java -jar TiltMaze.jar [options]");
        System.out.println("");
        System.out.println("Startup:");
        System.out.println("  no argument       starts up GUI");
        System.out.println("  -h                displays this help");
        System.out.println("  -s FILENAME       starts in solver mode");
        System.out.println("  -g ROWSIZE        starts in generator mode");
        System.out.println("  -a FILENAME       prints out statistics of the maze in FILENAME");
        System.out.println("");
        System.out.println("Solver mode:");
        System.out.println("  -s FILENAME       solves maze located in FILENAME");
        System.out.println("  -gml GMLFILE      saves state graph of the maze in GMLFILE");
        System.out.println("");
        System.out.println("Generator mode:");
        System.out.println("  -g ROWSIZE        generates a maze with ROWSIZE rows");
        System.out.println("  -col COLSIZE      generated maze will have COLSIZE columns");
        System.out.println("  -ch NUM           specifies number of squares");
        System.out.println("  -o FILENAME       generated maze will be printed to FILENAME");
        System.out.println("  -in FILENAME      use maze in FILENAME as initial candidate for maze generation");
        System.out.println("  -t SEC            max. time the generator is allowed to use");
        System.out.println("  -fit NUM          specifies fitness function");
        System.out.println("");
        System.out.println("The stats are printed in the following order:");
        System.out.println("  dim               dimensions of the maze");
        System.out.println("  ch                number of squares");
        System.out.println("  length            length of the shortest solution");
        System.out.println("  N                 number of nodes in the state graph");
        System.out.println("  E                 number of edges in the state graph");
        System.out.println("  Nd                number of deadlock nodes in the state graph");
        System.out.println("  Ed                number of deadlock edges in the state graph");
        System.out.println("  P(Ed)             portion of deadlock edges in the state graph");
        System.out.println("  ES                number of edges in the simplified state graph");
        System.out.println("  ESd               number of deadlock edges in the simplified state graph");
        System.out.println("  P(ESd)            portion of deadlock edges in the simplified state graph");
    }

    public static void displayWrongArgumentsWarning() {
        System.out.println("Usage: java -jar TiltMaze.jar [options]");
        System.out.println("");
        System.out.println("Try -h for more help.");
    }

    public static void displayGUI() {
        try {
            UIManager.setLookAndFeel(
                    UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
        JFrame jframe = new GeneratorFrame();
    }
}
